
// VS_BEGIN
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aCoord;

uniform mat4 u_model;

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
};

out vec2 Coord;

void main() {
    Coord = aCoord;
    gl_Position = vec4(aPos, 1.0f);
}
// VS_END
// FS_BEGIN
#version 330 core 
layout (location = 0) out vec4 SSAO;

// Light Packet:
// position.x position.y position.z type(PointLight: 0; DirectLight: 1; AmbientSphereLight: 2)
// color.r    color.g    color.b    strength
// direct.x   direct.y   direct.z   unuse
// unuse      unuse      unuse      unuse
layout (std140) uniform LightUBO
{
    mat4 u_lights[64];
    int u_lightNum;
};

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
};

uniform sampler2D u_positionRT;
uniform sampler2D u_normalRT;
uniform sampler2D u_tangentRT;
uniform sampler2D u_ssaoNoise;

uniform int u_kernelSize;
uniform float u_radius;
uniform vec3 u_samples[64];

in vec2 Coord;

out vec4 FragColor;

vec3 GetFragPos(vec3 vertex) {
    vec4 temp = u_project * vec4(vertex, 1.0f);
    return temp.xyz / temp.w;
}

void main() {
    vec2 size = textureSize(u_positionRT, 0) / 4.0f;
    vec3 position = texture(u_positionRT, Coord).xyz;
    vec3 normal = normalize(texture(u_normalRT, Coord).xyz);
    vec3 randomVec = texture(u_ssaoNoise, Coord * size).xyz;
    vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
    // vec3 tangent = normalize(texture(u_tangentRT, Coord).xyz);
    vec3 biTangent = cross(normal, tangent);
    mat3 TBN = mat3(tangent, biTangent, normal);

    if (position == vec3(0.0f)) {
        SSAO = vec4(0.0f);
        return;
    }

    float occlusion = 0.0f;
    for (int i = 0; i < u_kernelSize; ++i) {
        vec3 samplePos = position + TBN * u_samples[i]; // view space
        vec3 fragPos = GetFragPos(samplePos) * 0.5f + 0.5f; // [0, 1]
        float depth = texture(u_positionRT, fragPos.xy).z;
        float sampleDepth = samplePos.z;
        float rangeCheck = smoothstep(0.0, 1.0, u_radius / abs(depth - sampleDepth));
        occlusion += (sampleDepth <= depth ? 1.0 : 0.0) * rangeCheck; 
    }
    occlusion = occlusion / u_kernelSize;
    SSAO = vec4(vec3(0.0f), occlusion - 0.1f);
}
// FS_END
